/**
 *
 * Created by hjqi on 2016/4/8.
 * @RequestMapping("/apiApplication/xxx")
 * require 3-party lib
 */
var express = require('express');
var router = express.Router();
var _k8s_adp = require('../lib/k8s/k8sAdpter');
var libUserAcc = require('../lib/user/userAccount');
var _userAcc  = new libUserAcc();

var _getlimits = require('../lib/common/common').getLimitsFromService,
    isOwnEmpty = require('../lib/common/common').isOwnEmpty ,
    _getlimits_release = require('../lib/common/common').getLimitsFromServiceForRelease,
    _getlimitsUpdate = require('../lib/common/common').getLimitsFromServiceUpt,
    _getlimitsScale = require('../lib/common/common').getLimitsFromServiceScale,
    _checkIfFreeHost = require('../lib/common/common').checkIfFreeHost,
    startWith = require('../lib/common/common').startWith,
    myRet = require('../lib/common/common').myReturn;

var logger = require('../lib/log4js/log4js').logger('apiApplication');

/**
 *  @api {post} /apiApplication/createApplication Create a Application
 *  @apiVersion 2.0.0
 *  @apiName CreateApplication
 *  @apiGroup Application
 *  @apiPermission user
 *
 *  @apiDescription create an application. \n
 *  TODO   update resource should use two phase commit and not sync like this ,
 *            so currently, it don't process rollback or errors when update failed
 *
 *  @apiParam (Request Fields) {Object} service  service object
 *  @apiParam (Request Fields) {String} service.app  service name
 *
 */
router.post('/createApplication',function(req, res, next){
    var _data =  req.body;
    var _username = req.username;

    var _svc = _data;
    var _limit = _getlimits(_data);
    //the code below if deprecated
    // _userAcc.checkAccountBalance(_username,_limit).then(function(){
    //     return _k8s_adp.getK8s(_svc.node.clusterId);
    // }).then(function(_k8s){
    //     _svc.node.secret = req.secret;
    //     return _k8s.createAppService(_username,_svc);
    // })
    // //success update account db
    // .then(function(ret){
    //     return _userAcc.requestResourceUpdate(_username,_limit);
    // }).then(function(ret){
    //     res.send(ret);
    // }).catch(function(e){
    //     logger.error("createApplication.err: username:%s, service name:%s, error info:", _username, _data.app, e);
    //     res.status(400);
    //     res.send(e.message);
    // });
    //limit.cores &&  memory >= limit.memory
    if( _limit ){
        logger.debug("limit.cores"+_limit.cores+",limit.memory"+ _limit.memory ) ;
    }
    //it's ugly to  check and update like this
    _k8s_adp.getK8s(_svc.node.clusterId).then(function( _k8s ){
        if( isHostPathSvc(_svc) ){
            //自由主机不需要计算资源
            return emptyPromise( _k8s ) ;
        }else{
            return calculateResources(_k8s,_username,_limit,_svc.node.clusterId );
        }
    }).then(function(_k8s){
        _svc.node.secret = req.secret;
        return _k8s.createAppService(_username,_svc);
    }) //success update account db
    .then(function(ret){
       // return _userAcc.requestResourceUpdate(_username,_limit);
        return emptyPromise(true) ;
    }).then(function(ret){
        var result = {
            ret:true,
            error:null ,
            data:null
        }
         res.send( result );
    }).catch(function(e){
         logger.error("createApplication.err: username:%s, service name:%s, error info:", _username, _data.app, e.error);
        /*if( e && !e.messag ){
            if( e.error &&()) {
                e.error = JSON.parse( e.error ) ;typeof e.error ==  "string"
            }else{
                e.message = e ;
            }
            e = {
                "message":"Can not crate application !"+(e.message||e.error.message)
            }
        }*/
        res.status(200);
        /*var ret = {
            ret:false,
            error:e.message ,
            data:null
        }*/
        res.send( e );
    });
});

router.post('/deleteApplication',function(req, res, next){
    var _data =  req.body;
    var _username = req.username;
    var _svc = _data.svc;

    //delete no need to check resource
    _k8s_adp.getK8s(_svc.node.clusterId).then(function(_k8s){
        return _k8s.deleteAppService(_username,_svc,_data.isDelVolume);
    }).then(function(){
        return emptyPromise(true) ;
    }).then(function(ret){
        var result = {
            ret: true ,
            error: null  ,
            data: ret
        }
        res.send( result );
    }).catch(function(e){
        var _err_str = e.message || e.error;
        logger.error("deleteApplication.err: username:%s, service name:%s, error info:", _username, _data.app, _err_str );
        var result = {
            ret: false ,
            error: _err_str,
            data: _err_str
        }
        res.send( result );
    });
});
router.get('/getApplications',function(req, res, next){
    var _username = req.username;
    var serviceName = req.query.servicename;
    var clusterId = req.query.clusterId;
    //service list only search db
    //_k8s = _k8s_adp.getK8s(clusterId);
    _k8s_adp.getK8s(clusterId).then(function(_k8s){
        return _k8s.getAppServices(_username, serviceName,clusterId);
    }).then(function(ret){
        var result = {
            ret:true,
            error:null ,
            data: ret
        }
        res.send( result );
    }).catch(function(e){
        logger.error("#getApplications.err: username:%s, service name:%s, error info:", _username, serviceName, e) ;
        res.status(400);
        if(e&&!e.message ){//not every e has attribute message
            var e = {
                message:"query failed"
            } ;
        }
        var result = {
            ret: false,
            error: e.message ,
            data:  e.message
        }
        res.send( result );
    });
});

router.post('/updateApplication',function(req, res, next){
    var _data =  req.body;
    var _username = req.username;
    var _svc = _data;
    var _limit = undefined ;
    /**
     * because calculate resource quotas will get data from api-server.
     * when stop the application ,the real operation is delete the pods,so actually
     * updating will need calculate the required resources of all pods.
     **/
    if(_data.oldsvc.totalStatue ==="running" ){
        _limit = _getlimitsUpdate(_data.oldsvc,_data.newsvc);
    }else{
        _limit = _getlimits(_data.newsvc);
    }

    if( _limit ){
        logger.debug("/updateApplication->required.limit.cores"+_limit.cores+",limit.memory"+ _limit.memory ) ;
    }
    _k8s_adp.getK8s(_svc.oldsvc.node.clusterId).then(function(_k8s){
        return calculateResources(_k8s,_username,_limit , _svc.oldsvc.node.clusterId ) ;
    }).then(function(_k8s){
        if( !checkImage(_data.newsvc)   ){
            throw "No image specified!" ;
        }
        return _k8s.updateAppService(_username,_data.newsvc,_data.oldsvc);
    }) //success update account db
    .then(function(){
        // return _userAcc.requestResourceUpdate(_username,_limit);
        return emptyPromise(true) ;
    }).then(function(ret){
        var result = {
            ret:true,
            error:null ,
            data:ret
        }
        res.send( result );
    }).catch(function(e){
        if(e&&!e.message ){
            var e = {
                message:"update failed"
            } ;
        }
        logger.error("updateApplication error: username:%s, service name:%s, error info:", _username, _data.app, e);
        res.status(400);
        res.send(e.message?e.message:e.Message);
    });
});

router.post('/getPodStatus',function(req, res, next){
    var _data =  req.body;
    var _username = req.username;
    var _svc = _data;

    _k8s_adp.getK8s(_svc.node.clusterId).then(function(_k8s){
        logger.debug("send a request :"+ _username+","+_svc.app+","+_svc.ver) ;
        return _k8s.getAppPodStatus(_username,_svc.app,_svc.ver);
    }).then(function(ret){
        var result = {
            ret:true,
            error:null ,
            data: ret
        }

        res.send( result );
    }).catch(function(e){
        if(e&&!e.message ){
            e = {
                message:"query failed"
            } ;
        }
        logger.error("getPodStatus error: username:%s, service name:%s, error info:", _username, _data.app, e);
        var result = {
            ret:false,
            error:e.message  ,
            data: e.message
        }
        res.send( result );
    });
});
/*
*接口数据格式{
*   "app":"",
*   "testVersion":"",
*   "clusterId":"",
*   "rc":{
*       <格式参考https://kubernetes.io/docs/api-reference/v1.5/#replicationcontroller-v1>
*   }
* }
*/
router.post('/addTestVersionRc',function(req, res, next) {
    var data=req.body;
    var ns=req.username;
    _k8s_adp.getK8s(data.clusterId).then(function(_k8s){
        return _k8s.addTestVersionRc( ns, data.rc);
    }).then(function(ret){
        res.send(ret);
    }).catch(function(e){
        if(e&&!e.message ) {
            e = {
                message: "query failed"
            };
        }
        res.status(400);
        res.send(e.message);
    });
});
router.post('/deleteTestVersionRc',function(req, res, next) {
    var data=req.body;
    var ns=req.username;
    _k8s_adp.getK8s(data.clusterId).then(function(_k8s){
        return _k8s.deleteTestVersionRc( ns, data.app);
    }).then(function(ret){
        res.send(ret);
    }).catch(function(e){
        if(e&&!e.message ) {
            e = {
                message: "query failed"
            };
        }
        res.status(400);
        res.send(e.message);
    });
});
router.post('/publishTestVersionRc',function(req, res, next) {
    var data=req.body;
    var ns=req.username;
    _k8s_adp.getK8s(data.clusterId).then(function(_k8s){
        return _k8s.publishTestVersionRc( ns, data.app);
    }).then(function(ret){
        res.send(ret);
    }).catch(function(e){
        if(e&&!e.message ) {
            e = {
                message: "query failed"
            };
        }
        res.status(400);
        res.send(e.message);
    });
});

router.post('/getRc',function(req, res, next){
    var _data =  req.body;
    var _username = req.username;
    var _svc = _data;

    _k8s_adp.getK8s(_svc.node.clusterId).then(function(_k8s){
        return _k8s.getAppRC(_username,_svc.app,_svc.ver);
    }).then(function(ret){
        res.send(ret);
    }).catch(function(e){
        if(e&&!e.message ){
            e = {
                message:"query failed"
            } ;
        }
        logger.error("getPodStatus error: username:%s, service name:%s, error info:", _username, _data.app, e);
        res.status(400);
        res.send(e.message);
    });
});


router.post('/getRcSimple',function(req, res, next){
    var _data =  req.body;
    var _username = req.username;
    var _svc = _data;

    _k8s_adp.getK8s(_svc.node.clusterId).then(function(_k8s){
        return _k8s.getAppRCSimple(_username,_svc.app,_svc.ver);
    }).then(function(ret){
        res.send(ret);
    }).catch(function(e){
        if(e&&!e.message ){
            e = {
                message:"query failed"
            } ;
        }
        logger.error("getPodStatus error: username:%s, service name:%s, error info:", _username, _data.app, e);
        res.status(400);
        res.send(e.message);
    });
});
/**
 * get pod info from api-server
 * {
 *  "clusterId":"5e213ab323cd33",
 *  "item":"nature11-v1.9.14-alpine-8i71r"
 * }
 */
router.get('/getPodByName',function(req, res, next){
    var _data =  req.query;
    var _username = req.username;

    _k8s_adp.getK8s(_data.clusterId).then(function(_k8s){
        //_svc.item is pod name
        return _k8s.getPodsByPodName(_username,_data.item);
    }).then(function(ret){
        res.send(ret);
    }).catch(function(e){
        if(e&&!e.message ){
            e = {
                message:"query failed"
            } ;
        }
        logger.error("getPodByName error: username:%s, service name:%s, error info:", _username, _data.app, e);
        res.status(400);
        res.send(e.message);
    });
});

router.post('/getDefaultPodStatus',function(req, res, next){
    var _data =  req.body;
    var _username = req.username;
    var _svc = _data;

    //default pod is only for storage service , and put it in naturecloud side
    _k8s_adp.getK8s().then(function(_k8s){
        return _k8s.getAppPodStatus('default',_data.app);
    }).then(function(ret){
        res.send(ret);
    }).catch(function(e){
        if(e&&!e.message ){
            e = {
                message:"query failed"
            } ;
        }
        logger.error("getDefaultPodStatus error: username:%s, service name:%s, error info:", _username, _data.app, e);
        res.status(400);
        res.send(e.message);
    });
});
router.get('/getPodLog',function(req, res, next){
    var _username = req.username;
    var param = req.query;
    var instancename = param.instancename;
    var clusterId = param.clusterId;
    var sinceTime = param.sinceTime;

    //need to pass cluster id to backend
    //_k8s = _k8s_adp.getK8s(param.clusterId);
    _k8s_adp.getK8s(clusterId).then(function(_k8s){
        return _k8s.getAppPodLog(_username,instancename,sinceTime);
    }).then(function(ret){
        res.send(ret);
    }).catch(function(e){
        if(e&&!e.message ){
            e = {
                message:"query failed"
            } ;
        }
        logger.error("getDefaultPodStatus error: username:%s,error info:", _username , e);
        res.status(400);
        res.send(e.message);
    });
});

router.get('/getEvents',function(req, res){
    var _username = req.username;
    var param = req.query;
    var instanceName = param.instancename;
    var clusterId = param.clusterId;

    _k8s_adp.getK8s(clusterId).then(function(_k8s){
        return _k8s.getAppPodEvents(_username,instanceName,param.type);
    }).then(function(ret){
        var arr = [];
        var msg ="No data found";

        if( ret === null || ret === undefined ){
            logger.debug("no data !") ;
        }else{
            //parse event info
            var items = ret.items ;
            if( items && items.length > 0 ){
                //sorted by pod creating status asc
                for(var i in  items){
                    var event = {} ;
                    event.uid = items[i].metadata.uid ;
                    event.reason =items[i].reason ;
                    var message = items[i].message+""
                    if(  items[i].message&&  message .indexOf(instanceName ) == -1 ){
                        event.message="pod ("+instanceName+") "+message ;
                    }else{
                        event.message= message ;
                    }
                    arr.push( event ) ;
                }
                msg = "Success" ;
            }else{
                msg = "No data" ;
            }
        }
        res.send({
            data:arr,
            message:msg,
            code:arr.length==0?1:0
        });
    }).catch(function(e){
        logger.error("getDefaultPodStatus error: username:%s,instanceName:%s,error info:", _username ,instanceName, e);
        if( !e.message ){
            e = {
                "message" : e
            }
        }
        res.status(400);
        res.send( e.message );
    });
});

//it usually control service start or stop
router.post('/modifyRc',function(req, res, next){
    var _username = req.username;
    var param =  req.body || {} ;
    var svc = param.data;
    var _scaleNum = param.replicas;
    var _rcId = svc.app+'-v'+svc.ver;
    var _limit ={};
    var orgNum = 0;
    if(param.forceDelete){
        svc['forceDelete']=true ;
    }
    if(param.op === 'start' ) {
        orgNum = 0;
        _limit = _getlimits(param.data);
    }
    //assert that rcnum 0 is service stop
    else if(_scaleNum === 0){
        param.op = 'stop';
    }
    else {
        orgNum = svc.rcnum;
        _limit = _getlimitsScale(param.data, _scaleNum);
    }

    //_k8s = _k8s_adp.getK8s(svc.clusterId);
    //1.calc the if user's resource quotas if enough
    //2.modify Rc
    _k8s_adp.getK8s(svc.node.clusterId).then(function(_k8s) {
        if( param.limitCheck ==='yes'){
            //if checked before ,then don't check again
            logger.debug("param.limitCheck "+param.limitCheck ) ;
            return emptyPromise( _k8s ) ;
        }else{
            return calculateResources(_k8s,_username,_limit , svc.node.clusterId ) ;
        }
    }).then(function(_k8s){
        return _k8s.modifyReplicationController(_username, _rcId, _scaleNum, orgNum, svc,param.op);
    }).then(function(ret){
        res.send( ret );
    }).catch(function(e){

        logger.error("modifyRC username:%s, service name:%s, error info:", _username, svc.app, e.error|| e.message);
        if(e instanceof Error)
            res.send(myRet(false, e.message,e.message));
        else
            res.send(e);
    });

});

router.post('/grayudp',function(req, res, next){
    var param =  req.body;

    var svc = param.data;
    var _username = svc.username;
    var newversion = param.ver;

    //gray update will cost many time , so clear timeout
    if(  req.clearTimeout ){
        logger.debug("" +logger.debug ) ;
        req.clearTimeout(); //我赵日天服了，根本没这个方法，测试是不会测试的，if判断又不会，直接加上了，管他有没有方法，
        //真的是忍无可忍了，赵日天只能再次加个if来判断clearTimeout函数是否存在了。16/11/25
    }
    //_k8s = _k8s_adp.getK8s(svc.clusterId);
    _k8s_adp.getK8s(svc.node.clusterId).then(function(_k8s){
        return _k8s.grayUpdate(_username,svc,newversion);
    }).then(function(svc){
        var result = {
            ret:true,
            error:null ,
            data: svc
        }
        res.send( result );
    }).catch(function(e){
        logger.error("grayudp error: username:%s, service name:%s, error info:", _username, svc.app, e);
        return res.status(400).send(e);
    });

});
//自动更新调用
router.post('/autoupd',function(req, res, next){
    var param =  req.body;

    var svc = param.data;
    var _username = svc.username;
    var newversion = param.ver;

    if(  req.clearTimeout ){
        logger.debug("" +logger.debug ) ;
        req.clearTimeout();
    }
    _k8s_adp.getK8s(svc.node.clusterId).then(function(_k8s){
        res.send('connection success');
        return _k8s.grayUpdate(_username,svc,newversion);
    }).catch(function(e){
        logger.error("grayudp error: username:%s, service name:%s, error info:", _username, svc.app, e);
        return res.status(400).send(e);
    });
});
/**
 * 更改DB中serviceInfo的状态
 */
router.post('/updateAppStatus',function(req, res, next){
    var _data =  req.body;
    var _username = req.username;

    var _svc = _data.svc.dbJson;
    _k8s_adp.getK8s(_svc.node.clusterId).then(function(_k8s){
        return _k8s.updateAppStatus(_username,_svc.app,_data.status);
    }).then(function(ret){
        var result = {
            ret:true,
            error:null ,
            data: ret
        }
        res.send( result );
    }).catch(function(e){
        logger.info("#updateAppStatus:"+ JSON.stringify( e )) ;
        var result = {
            ret:false,
            error: "Updating app status failed ,appConfigEnv error!"  ,
            data:  "Updating app status failed ,appConfigEnv error!"
        }
        res.send( result  );
    });
});
router.post('/updateAutoStatus', function (req,res,next) {
    var _data=req.body;
    var _username=req.username;
    var _svc=_data.svc.dbJson;
    _k8s_adp.getK8s(_svc.node.clusterId).then(function(_k8s){
    _k8s.updateAutoStatus(_username,_svc.app,_data.autoStatus);
    }).then(function(ret){
        var result = {
            ret:true,
            error:null ,
            data: ret
        }
        res.send( result );
    })
});
router.post('/updateScaleStatus', function (req,res,next) {
    var _data=req.body;
    var _username=req.username;
    var _svc=_data.svc.dbJson;
    _k8s_adp.getK8s(_svc.node.clusterId).then(function(_k8s){
        _k8s.updateScaleStatus(_username,_svc.app,_data);
    }).then(function(ret){
        var result = {
            ret:true,
            error:null ,
            data: ret
        }
        res.send( result );
    })
});
/**
 * 检查用户的资源配额是否足够(启动，停止，重启)
 * ps：scale 需要考虑扩展之后会增加resources
 * param
 * {
        data:svc,
        status:status,
        replicas:scale_num,
        op:'start'
    }
 */
router.post('/checkResourceQuotas',function(req, res, next){
    var _username = req.username;
    var param =  req.body;
    var svc = param.data;
    var _scaleNum = param.replicas;
    var _rcId = svc.app+'-v'+svc.ver;
    var _limit ={};
    if(param.op === 'start'||'modifyReplicas' ) {
        _limit = _getlimits(param.data);
    }else {
        _limit = _getlimitsScale(param.data, _scaleNum);
    }
    _k8s_adp.getK8s(svc.node.clusterId).then(function(_k8s) {
        return calculateResources(_k8s,_username,_limit , svc.node.clusterId ) ;
    }).then(function(_k8s){
        var result = {
            ret:true,
            error: null  ,
            data:  true
        }
        res.send( result );
    }).catch(function(e){
        logger.error("checkResourceQuotas username:%s, service name:%s, error info:", _username, svc.app, e);
        if( e.message === undefined ){
            e= {
                "message":e
            };
        }
        var result = {
            ret: false ,
            error: e.message  ,
            data:  e.message
        }
        res.send( result );
    });

});

/**
 *   update self host node ip info in k8s handler which cached in memory
 */
router.post('/updateSelfhostIpInfo',function(req, res, next){
    var nodeInfo =  req.body;
    _k8s_adp.setK8sHandlerNodeIP(nodeInfo);
    res.send(true);
}) ;

function opSelect(op,k8s,parameters){
 logger.debug("op is "+op) ;
 if( "create" === op ){
     return k8s.CreateAutoScale( parameters ) ;
 }else if("delete" === op ){
     return k8s.DeleteAutoScale( parameters ) ;
 }else if("list" === op ){
     return k8s.ListAutoScale( parameters ) ;
 }else if("deletes" === op ){
     return k8s.DeleteAllAutoScale(parameters);
 }else if("replace" === op ){
     return k8s.ReplaceAutoScale( parameters ) ;
 }else if("find" === op ){
     return k8s.FindAutoScale( parameters ) ;
 }else{
     logger.debug("no op matched")
     return emptyPromise();
 }

}

/**
 * pod auto scaling operations --start--
 * Created by dell2 on 2017/2/6.
 * [create,list,find]response template:
 * "data" : {
		"scaleTargetRef" : {
			"kind" : "ReplicationController",
			"name" : "node4-test-v2.0.4.1"
		},
		"minReplicas" : 1,
		"maxReplicas" : 2,
		"targetCPUUtilizationPercentage" : 80,
		"status" : {
			"currentReplicas" : 1,
			"desiredReplicas" : 0
		}
	}
 *
 */

router.post('/createPodAutoScale',function(req, res, next){
    var parameters =  req.body;
    var username = req.username;
    var op = "create" ;//operations:create,delete,list,deletes,replace,find

    if( !parameters || isOwnEmpty(parameters) ){
        //schema of parameters below ;
        // parameters = {
        //     scaleName : "scale-test",
        //     max : 2,
        //     min : 1 ,
        //     refKind : "ReplicationController",
        //     refName : "node4-test-v2.0.4.1",
        //     cpuPct : 80
        // }
        handlerError(op,res,username,"No auto scale entity info specified" ) ;
        return ;
    }
    parameters["namespace"] = username ;
    handleHttpRequest( op ,parameters,res ) ;
});

router.post('/replaceAutoScale',function(req, res, next){
//router.get('/replaceAutoScale',function(req, res, next){      //http get just for test
    var parameters =  req.body;
    var username = req.username;
    var op = "replace" ;//operations:create,delete,list,deletes,replace,find

    if( !parameters || isOwnEmpty(parameters) ){
        //DEBUG  below codes just for test
        // var cpuPct = 80 ;
        // if( op === "replace" ){
        //     cpuPct = 90 ;
        // }
        // parameters = {
        //     scaleName : "scale-test",
        //     max : 2,
        //     min : 1 ,
        //     refKind : "ReplicationController",
        //     refName : "node4-test-v2.0.4.1",
        //     cpuPct : cpuPct
        // }
        handlerError(op,res,username,"No auto scale entity info specified" ) ;
        return ;
    }
    parameters["namespace"] = username ;
    handleHttpRequest( op ,parameters,res ) ;
});

/**
 * delete the xxx
 * @paramater
        scaleName : "scale-test",
        namespace : "fanjun",
 * @return
 * {
        "ret" : true,
        "error" : null,
        "data" : {
            "status" : "Success"
        }
    }
 */
router.get('/deletePodAutoScale',function(req, res, next){      //http get just for test
    var op = "delete" ;//operations:create,delete,list,deletes,replace,find
    var parameters =  {};
    var username = req.username;
    var scaleName = req.query.scaleName ||"";
    var clusterId = req.query.clusterId   ;

    parameters["clusterId"] = clusterId;
    parameters["scaleName"] = scaleName;
    parameters["namespace"] = username ;
    handleHttpRequest( op ,parameters,res ) ;
});

router.get('/deleteAllPodAutoScale',function(req, res, next){      //http get just for test
    var op = "deletes" ;//operations:create,delete,list,deletes,replace,find
    var parameters =  {};
    var username = req.username;
    var clusterId = req.query.clusterId   ;

    parameters["clusterId"] = clusterId;
    parameters["namespace"] = username ;
    handleHttpRequest( op ,parameters,res ) ;
});

router.get('/listPodAutoScale',function(req, res, next){      //http get just for test
    var op = "list" ;//operations:create,delete,list,deletes,replace,find
    var parameters =  {};
    var username = req.username;
    var clusterId = req.query.clusterId   ;

    parameters["clusterId"] = clusterId;
    parameters["namespace"] = username ;
    handleHttpRequest( op ,parameters,res ) ;
});

router.get('/findPodAutoScale',function(req, res, next){      //http get just for test
    var op = "find" ;//operations:create,delete,list,deletes,replace,find
    var parameters =  {};
    var username = req.username;
    var scaleName = req.query.scaleName ||"" ;
    var clusterId = req.query.clusterId  ;

    parameters["clusterId"] = clusterId;
    parameters["scaleName"] = scaleName;
    parameters["namespace"] = username ;
    handleHttpRequest( op ,parameters,res ) ;
});

function handleHttpRequest(op,parameters,res){
    var username = parameters.namespace ;
    if( !parameters || isOwnEmpty(parameters) ){
        logger.error( "No auto scale entity info specified" ) ;
    }
    _k8s_adp.getK8s(parameters.clusterId).then(function( k8s ){
        return opSelect(op,k8s,parameters) ;
    }).then(function( response){
        var _data = response ;
        logger.debug( "response "+ JSON.stringify( response) ) ;
        if( null != response && !isOwnEmpty( response )){
            if( op ==="list" ){
                //return list of items
                _data= parsePodAutoScaleList( response ) ;
            }else if( op ==="deletes" ){
                //return list of items
                var list= parsePodAutoScaleList( response ) ;
                if( list && list.length > 0 ){
                    _data["status"] = "Success" ;
                    _data["message"] = "Data deleted" ;
                }else{
                    _data["reason"] = "No data exist" ;
                    _data["message"] = "No data exist" ;
                    _data["status"] = "Failure" ;
                }
            }else { //it's redundancy
                _data = response["spec"] || {};
                _data["current"] =  response["status"] ;
                _data["status"] = "Success" ;
            }
        }
        var result = {
            ret:true,
            error:null ,
            data:_data
        }
        res.send( result );
    }).catch(function(e){
        e = parseFailResult(e ) ;
        logger.error(op+" PodAutoScale err: username:%s, service name:%s, error info:", username, parameters.app, e );
        var ret = {
            ret:false,
            error:e.message  ,
            data:e
        }
        res.status(200);
        res.send( ret );
    }); ;
}

function handlerError(op,res,username,message){
    logger.error(op+" PodAutoScale err: username:%s, service name:%s, error info:", username, null );
    var ret = {
        ret:false,
        error:message  ,
        data:e
    }
    res.status(200);
    res.send( ret );
}

function parseFailResult(err){
    var data = { };
    if( err && !isOwnEmpty(err ) ){
        data["reason"] = err["reason"] ;
        data["message"] = err["message"] ;
        data["status"] = err["status"] ;
    }else{
        data["message"] = err ;
    }
    return data ;
}

/**
 * parse the list of AutoScaler
 * {
	"kind" : "HorizontalPodAutoscalerList",
	"apiVersion" : "autoscaling/v1",
	"metadata" : {
		"selfLink" : "/apis/autoscaling/v1/namespaces/fanjun/horizontalpodautoscalers",
		"resourceVersion" : "13140909"
	},
	"items" : [{
			"metadata" : {
				"name" : "autotest",
				"namespace" : "fanjun",
				"selfLink" : "/apis/autoscaling/v1/namespaces/fanjun/horizontalpodautoscalers/autotest",
				"uid" : "1db39385-ec55-11e6-a484-00163e04582e",
				"resourceVersion" : "13033711",
				"creationTimestamp" : "2017-02-06T10:14:59Z"
			},
			"spec" : {
				"scaleTargetRef" : {
					"kind" : "ReplicationController",
					"name" : "node4-test-v2.0.4.1"
				},
				"minReplicas" : 1,
				"maxReplicas" : 2,
				"targetCPUUtilizationPercentage" : 80
			},
			"status" : {
				"currentReplicas" : 1,
				"desiredReplicas" : 0
			}
		},  ...
	]
}
 * @param response
 */
function parsePodAutoScaleList(response){
    if( !response ){
        logger.error("No AutoScaler specified") ;
    }
    var list = [] ;
    var items = response["items"] ;
    if( items && items.length > 0 ){
        items.forEach(function ( one ) {
            var data = one["spec"] || {}  ;
            data["name"] = one["metadata"].name ;
            data["status"] =  one["status"] ;
            list.push( data ) ;
        });
    }
    return list ;
}

/**
 * pod auto scaling operations --end--
 */

/**
 * check the used resource quotas, get the quotas from the api-server
 */
function calculateResources(_k8s,userName ,_limit,clusterId) {
    logger.debug( "calculateResources.clusterId="+ clusterId) ;
    if( _checkIfFreeHost( clusterId )){
        //just skip
        return new Promise(function (resolve,reject) {
            resolve(_k8s) ;
        }) ;
    }

    return new Promise(function (resolve,reject) {
        var ret = false ;
        _k8s.getPodsWithComposeName(userName,"").then( function(rets){
            var cores = 0 ;
            var memory = 0 ;
            //go through the pods list and sum the total cores and memories
            if( rets !== undefined && rets.items && rets.items.length > 0 ){
                //logger.debug("Get pods list:\n"+ JSON.stringify(rets) ) ;
                var items =  rets.items;
                for(var x in   items ){
                    var containers = items[x].spec.containers;
                    // "status": {
                    //     "phase": "Failed",
                    //         "message": "Pod Node didn't have enough resource: CPU, requested: 125, used: 1935, capacity: 2000",
                    //         "reason": "OutOfCPU",
                    //         "startTime": "2016-09-28T09:11:34Z"
                    // }
                    //出现创建pod失败,Terminating的情况下，该接口也会返回这个pod，尽管实际不占用资源
                    //此处需要判断pod是否是失败的,ps正常情创建超过况下是不会出现的，
                    // 因为createApplication的时候也会判断是否创建成功。
                    if( items[x].status.phase ==="Failed" || items[x].status.phase ==="Terminating" ){
                        logger.info(items[x].metadata.name+" schedule "+items[x].status.phase ) ;
                        continue ;
                    }

                    if( containers && containers.length > 0 ){
                        for(var y in containers ){
                            var res =  containers[y].resources ;
                            //  "resources" : {
                            //     "limits" : {
                            //           "cpu" : "125m",
                            //            "memory" : "128Mi"
                            //     },
                            //     "requests" : {
                            //           "cpu" : "125m",
                            //            "memory" : "128Mi"
                            //     }
                            //   }
                            if( res && res.requests){
                                cores+= humanizeCpuCores(  res.requests.cpu ) ;
                                memory+= getMemoryUsage(  res.requests.memory ) ;
                            }
                        }
                    }
                }//-for item ...-
                logger.debug( "get all pods's occupied resources->cores:"+ cores+",memory:"+ memory ) ;
                checkResources(userName,cores,memory,_limit).then(function (){
                    logger.debug("resources is sufficient!!") ;
                    resolve(_k8s) ;
                }).catch(function (err) {
                    /*reject({
                        "message":err ,
                        "Cores":cores,
                        "Memory":memory,
                        "Required":_limit
                    });*/
                    reject(err);
                });
            }else{
                logger.info("there are no occupied resources by this application") ;
                //检查本次请求的资源是否是小于用户所拥有的资源
                checkResources(userName, 0,0,_limit ).then(function () {
                    resolve(_k8s) ;
                }).catch(function (err) {
                    /*reject(myRet(false,err, {
                        "message": err ,
                        "Cores":cores,
                        "Memory":memory,
                        "Required":_limit
                    } )) ;*/
                    reject(err);
                });
            }
        }).catch(function (err) {
            if( err === undefined ) {
                var err = {} ;
            }
            var message = "Can't get pods info under ns:"+userName+",err:"+JSON.stringify(err) ;
            logger.error( message ) ;
            reject(myRet(false, message));
        });
    }) ;
}
/**
 * check if there are sufficient resources.
 * such as:"cpu" : "125m",
 */
function checkResources(username,cores,memory,limit){
    return new Promise(function (resolve,reject) {
        _userAcc.calcRest(username,{
            "cores": cores,
            "memory": memory
        }).then(function ( rest ) {
            logger.debug( "Rest resources is :"+JSON.stringify( rest )+" and needed :"+JSON.stringify(limit) ) ;
            if( rest.cores >= limit.cores &&  rest.memory >= limit.memory){
                resolve() ;
            }else{
                reject(myRet(false,"resources quota not enough ! Rest resources is :"+JSON.stringify( rest )+" and needed :"+JSON.stringify(limit))) ;
            }
        }).catch(function (err) {
            reject(myRet(false,err.message));
        });
    }) ;
}
/**
 * change xm to y cores ,m means 1/1000
 * such as :"cpu" : "125m"
 */
function humanizeCpuCores(cores){
    if(cores && cores.indexOf("m") != -1 ){
        var num = unSubStr(cores,"m") ;
        var ret = num/1000 ;
        return isNaN(ret)?0:ret ;
    }
    return 0 ;
}
/**
 *  get rid of Mi,occupy will be xxxMi
 *  such as: "memory" : "128Mi"
 */
function getMemoryUsage(occupy){
    if(occupy && occupy.indexOf("Mi") != -1 ){
        var ret = unSubStr(occupy, "Mi") ;
        return isNaN(ret)?0:ret ;
    }
    return 0 ;
}
/**
 * get the str from source without target string
 */
function unSubStr(source,target) {
   return parseInt(source.substring(0, source.indexOf( target ) ) ) ;
}

function emptyPromise(data) {
    if(data === undefined ){
        var data = {};
    }
    return new Promise(function (resolve,reject) {
        resolve(data) ;
    }) ;
}

function updateServiceStatus(clusterId,username,appName,status){
    return new Promise(function (resolve, reject) {
            _k8s_adp.getK8s(clusterId).then(function (_k8s) {
                return _k8s.updateAppStatus(username, appName, status);
            }).then(function (ret) {
                resolve() ;
            }).catch(function (e) {
                logger.error("#updateServiceStatus:failed to update app status"+JSON.stringify( e ) ) ;
                reject( e ) ;
            });
    }) ;
}

/**
 * 判断是否是自由主机
 */
function isHostPathSvc(svc){
    svc = svc || {} ;
    if( svc.volumeType && svc.volumeType == "hostPath" ){
        return true ;
    }
    return false ;
}
/**
 * bug :避免出现镜像为undefined/library/xxx:xxx的情况
 */
function checkImage(svc ){
   if( svc && svc.node ){
       var image = svc.node.image ||"";
       if( image.indexOf('undefined') === -1 && image.indexOf('null') === -1   ){
            return true ;
       }
   }
    return false ;
}


module.exports = router;
